﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BCCommon
{
    /// <summary>
    /// 性能跟踪工具。
    /// </summary>
    public static class PerformanceTracer
    {
        /// <summary>
        /// 通过异步方式调用的方式处理一些不太重要的工作。
        /// </summary>
        /// <param name="action">指定要执行的操作。</param>
        public static void InvokeAsync(Action action)
        {
            Task.Run(action);
        }

        /// <summary>
        /// 使用并行 API 调用指定的一个方法。
        /// </summary>
        /// <param name="action">操作。</param>
        public static void InvokeAll(Action action)
        {
            InvokeAll(new Action[] { action });
        }

        /// <summary>
        /// 使用并行 API 调用指定的一组方法。
        /// </summary>
        /// <param name="action1">操作 1。</param>
        /// <param name="action2">操作 2。</param>
        public static void InvokeAll(Action action1, Action action2)
        {
            InvokeAll(new Action[] { action1, action2 });
        }

        /// <summary>
        /// 使用并行 API 调用指定的一组方法。
        /// </summary>
        /// <param name="action1">操作 1。</param>
        /// <param name="action2">操作 2。</param>
        /// <param name="action3">操作 3。</param>
        public static void InvokeAll(Action action1, Action action2, Action action3)
        {
            InvokeAll(new Action[] { action1, action2, action3 });
        }

        /// <summary>
        /// 使用并行 API 调用指定的一组方法。
        /// </summary>
        /// <param name="action1">操作 1。</param>
        /// <param name="action2">操作 2。</param>
        /// <param name="action3">操作 3。</param>
        /// <param name="action4">操作 4。</param>
        public static void InvokeAll(Action action1, Action action2, Action action3, Action action4)
        {
            InvokeAll(new Action[] { action1, action2, action3, action4 });
        }

        /// <summary>
        /// 使用并行 API 调用指定的一组方法。
        /// </summary>
        /// <param name="action1">操作 1。</param>
        /// <param name="action2">操作 2。</param>
        /// <param name="action3">操作 3。</param>
        /// <param name="action4">操作 4。</param>
        /// <param name="action5">操作 5。</param>
        public static void InvokeAll(Action action1, Action action2, Action action3, Action action4, Action action5)
        {
            InvokeAll(new Action[] { action1, action2, action3, action4, action5 });
        }

        /// <summary>
        /// 使用并行 API 调用指定的一组方法。
        /// </summary>
        /// <param name="action1">操作 1。</param>
        /// <param name="action2">操作 2。</param>
        /// <param name="action3">操作 3。</param>
        /// <param name="action4">操作 4。</param>
        /// <param name="action5">操作 5。</param>
        /// <param name="action6">操作 6。</param>
        public static void InvokeAll(Action action1, Action action2, Action action3, Action action4, Action action5, Action action6)
        {
            InvokeAll(new Action[] { action1, action2, action3, action4, action5, action6 });
        }

        /// <summary>
        /// 使用并行 API 调用指定的一组方法。
        /// </summary>
        /// <param name="action1">操作 1。</param>
        /// <param name="action2">操作 2。</param>
        /// <param name="action3">操作 3。</param>
        /// <param name="action4">操作 4。</param>
        /// <param name="action5">操作 5。</param>
        /// <param name="action6">操作 6。</param>
        /// <param name="action7">操作 7。</param>
        public static void InvokeAll(Action action1, Action action2, Action action3, Action action4, Action action5, Action action6, Action action7)
        {
            InvokeAll(new Action[] { action1, action2, action3, action4, action5, action6, action7 });
        }

        /// <summary>
        /// 使用并行 API 调用指定的一组方法。
        /// </summary>
        /// <param name="action1">操作 1。</param>
        /// <param name="action2">操作 2。</param>
        /// <param name="action3">操作 3。</param>
        /// <param name="action4">操作 4。</param>
        /// <param name="action5">操作 5。</param>
        /// <param name="action6">操作 6。</param>
        /// <param name="action7">操作 7。</param>
        /// <param name="action8">操作 8。</param>
        public static void InvokeAll(Action action1, Action action2, Action action3, Action action4, Action action5, Action action6, Action action7, Action action8)
        {
            InvokeAll(new Action[] { action1, action2, action3, action4, action5, action6, action7, action8 });
        }

        /// <summary>
        /// 使用并行 API 调用指定的一组方法。
        /// </summary>
        /// <param name="action1">操作 1。</param>
        /// <param name="action2">操作 2。</param>
        /// <param name="action3">操作 3。</param>
        /// <param name="action4">操作 4。</param>
        /// <param name="action5">操作 5。</param>
        /// <param name="action6">操作 6。</param>
        /// <param name="action7">操作 7。</param>
        /// <param name="action8">操作 8。</param>
        /// <param name="action9">操作 9。</param>
        public static void InvokeAll(Action action1, Action action2, Action action3, Action action4, Action action5, Action action6, Action action7, Action action8, Action action9)
        {
            InvokeAll(new Action[] { action1, action2, action3, action4, action5, action6, action7, action8, action9 });
        }

        /// <summary>
        /// 使用并行 API 调用指定的一组方法。
        /// </summary>
        /// <param name="actions">一组操作。</param>
        public static void InvokeAll(Action[] actions)
        {
            try
            {
                Task.WaitAll(actions.Select(p => Task.Factory.StartNew(p)).ToArray());
            }
            catch (AggregateException ex)
            {
                throw ex.InnerExceptions.First();
            }
        }

        public static T Wait<T>(Task<T> task)
        {
            return task.GetAwaiter().GetResult();
        }

        public static (T1, T2) WaitAll<T1, T2>(Task<T1> task1, Task<T2> task2)
        {
            return (task1.GetAwaiter().GetResult(),
                task2.GetAwaiter().GetResult());
        }

        public static (T1, T2, T3) WaitAll<T1, T2, T3>(Task<T1> task1, Task<T2> task2, Task<T3> task3)
        {
            return (task1.GetAwaiter().GetResult(),
                task2.GetAwaiter().GetResult(),
                task3.GetAwaiter().GetResult());
        }

        public static (T1, T2, T3, T4) WaitAll<T1, T2, T3, T4>(Task<T1> task1, Task<T2> task2, Task<T3> task3, Task<T4> task4)
        {
            return (task1.GetAwaiter().GetResult(),
                task2.GetAwaiter().GetResult(),
                task3.GetAwaiter().GetResult(),
                task4.GetAwaiter().GetResult());
        }

        public static (T1, T2, T3, T4, T5) WaitAll<T1, T2, T3, T4, T5>(Task<T1> task1, Task<T2> task2, Task<T3> task3, Task<T4> task4, Task<T5> task5)
        {
            return (task1.GetAwaiter().GetResult(),
                task2.GetAwaiter().GetResult(),
                task3.GetAwaiter().GetResult(),
                task4.GetAwaiter().GetResult(),
                task5.GetAwaiter().GetResult());
        }

        public static (T1, T2, T3, T4, T5, T6) WaitAll<T1, T2, T3, T4, T5, T6>(Task<T1> task1, Task<T2> task2, Task<T3> task3, Task<T4> task4, Task<T5> task5, Task<T6> task6)
        {
            return (task1.GetAwaiter().GetResult(),
                task2.GetAwaiter().GetResult(),
                task3.GetAwaiter().GetResult(),
                task4.GetAwaiter().GetResult(),
                task5.GetAwaiter().GetResult(),
                task6.GetAwaiter().GetResult());
        }

        public static (T1, T2, T3, T4, T5, T6, T7) WaitAll<T1, T2, T3, T4, T5, T6, T7>(Task<T1> task1, Task<T2> task2, Task<T3> task3, Task<T4> task4, Task<T5> task5, Task<T6> task6, Task<T7> task7)
        {
            return (task1.GetAwaiter().GetResult(),
                task2.GetAwaiter().GetResult(),
                task3.GetAwaiter().GetResult(),
                task4.GetAwaiter().GetResult(),
                task5.GetAwaiter().GetResult(),
                task6.GetAwaiter().GetResult(),
                task7.GetAwaiter().GetResult());
        }

        public static (T1, T2, T3, T4, T5, T6, T7, T8) WaitAll<T1, T2, T3, T4, T5, T6, T7, T8>(Task<T1> task1, Task<T2> task2, Task<T3> task3, Task<T4> task4, Task<T5> task5, Task<T6> task6, Task<T7> task7, Task<T8> task8)
        {
            return (task1.GetAwaiter().GetResult(),
                task2.GetAwaiter().GetResult(),
                task3.GetAwaiter().GetResult(),
                task4.GetAwaiter().GetResult(),
                task5.GetAwaiter().GetResult(),
                task6.GetAwaiter().GetResult(),
                task7.GetAwaiter().GetResult(),
                task8.GetAwaiter().GetResult());
        }

        public static (T1, T2, T3, T4, T5, T6, T7, T8, T9) WaitAll<T1, T2, T3, T4, T5, T6, T7, T8, T9>(Task<T1> task1, Task<T2> task2, Task<T3> task3, Task<T4> task4, Task<T5> task5, Task<T6> task6, Task<T7> task7, Task<T8> task8, Task<T9> task9)
        {
            return (task1.GetAwaiter().GetResult(),
                task2.GetAwaiter().GetResult(),
                task3.GetAwaiter().GetResult(),
                task4.GetAwaiter().GetResult(),
                task5.GetAwaiter().GetResult(),
                task6.GetAwaiter().GetResult(),
                task7.GetAwaiter().GetResult(),
                task8.GetAwaiter().GetResult(),
                task9.GetAwaiter().GetResult());
        }
    }
}
